package com.zjk.toolkit.governance.aspect;

import com.zjk.toolkit.governance.annotations.DoHystrix;
import com.zjk.toolkit.governance.annotations.DoRateLimiter;
import com.zjk.toolkit.governance.annotations.DoWhiteList;
import com.zjk.toolkit.governance.config.WhiteListProperties;
import com.zjk.toolkit.governance.service.IGovernanceService;
import com.zjk.toolkit.governance.service.impl.HystrixServiceImpl;
import com.zjk.toolkit.governance.service.impl.RateLimiterServiceImpl;
import com.zjk.toolkit.governance.service.impl.WhiteListServiceImpl;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

@Aspect
@Component
public class GovernanceAspect {
    private static final Logger log = LoggerFactory.getLogger(GovernanceAspect.class);

    @Resource
    private WhiteListProperties properties;

    @Pointcut("@annotation(com.zjk.toolkit.governance.annotations.DoWhiteList)")
    public void whiteListPoint() {
    }
    @Pointcut("@annotation(com.zjk.toolkit.governance.annotations.DoHystrix)")
    public void hystrixPoint() {
    }
    @Pointcut("@annotation(com.zjk.toolkit.governance.annotations.DoRateLimiter)")
    public void rateLimitPoint() {
    }

    @Around("whiteListPoint() && @annotation(doWhiteList)")
    public Object doWhiteList(ProceedingJoinPoint joinPoint, DoWhiteList doWhiteList) throws Throwable {
        log.info("doWhiteList,白名单:{}",properties.getUsers());
        Method method = getMethod(joinPoint);
        IGovernanceService governanceService = new WhiteListServiceImpl(properties);
        return governanceService.access(joinPoint, method, doWhiteList, joinPoint.getArgs());
    }

    @Around("hystrixPoint() && @annotation(doHystrix)")
    public Object doHystrix(ProceedingJoinPoint joinPoint, DoHystrix doHystrix) throws Throwable {
        Method method = getMethod(joinPoint);
        IGovernanceService governanceService = new HystrixServiceImpl(doHystrix.timeout());
        return governanceService.access(joinPoint, method, doHystrix, joinPoint.getArgs());
    }

    @Around("rateLimitPoint() && @annotation(doRateLimiter)")
    public Object doRateLimiter(ProceedingJoinPoint joinPoint, DoRateLimiter doRateLimiter) throws Throwable {
        Method method = getMethod(joinPoint);
        IGovernanceService governanceService = new RateLimiterServiceImpl();
        return governanceService.access(joinPoint, method, doRateLimiter, joinPoint.getArgs());
    }

    public Method getMethod(ProceedingJoinPoint joinPoint) {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        try {
            return joinPoint.getTarget().getClass().getMethod(methodSignature.getName(), methodSignature.getParameterTypes());
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
